/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			uservar.cc
  \date			Dec 2011
  \author		TNick

  \brief		Contains the implementation for UserVar class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<pgscript.h>
#include	<pgscript_internal.h>

#include	<session.h>


#include	<module.h>
#include	<defvar.h>
#include	<build-in/uvarary.h>

#include	<pgsave/ipgsave.h>

#include	"uservar.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */

using namespace PgScr;

/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

extern findVariableStruct			uf_findVarStr;

/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
void			UserVar::construct			( Module * mdl )
{
	flg_ = FL_NONE;
	kb_ = NULL;
	val_ = NULL;
	data_.ty = VTY_INTEGER;
	data_.l = 0;

	/** @todo mdl->appendVar( this ); */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar::UserVar		( void )
{
	construct( Session::defModule() );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar::UserVar		( QString v_name, Module * mdl )
{
	if ( mdl == NULL )
	{
		mdl = Session::defModule();
	}
	construct( mdl );
	name_ = v_name;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar::UserVar		( QString v_name, Session * trg_ss )
{
	if ( trg_ss == NULL )
	{
		construct( Session::defModule() );
	}
	else
	{
		construct( trg_ss->sessionDefModule() );
	}
	name_ = v_name;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar::UserVar		(
		QString v_name, UserVar::Flags flgs,
		UserVar::kbUserVarChange kb_init,
		UserVar::kbUserVarValidate validator,
		Module * mdl )
{

	if ( mdl == NULL )
	{
		mdl = Session::defModule();
	}
	construct( mdl );

	name_ = v_name;
	flg_ = flgs;
	kb_ = kb_init;
	val_ = validator;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar::UserVar		(
		Session *trg_ss, QString v_name,
		Flags flgs,
		kbUserVarChange kb_init,
		kbUserVarValidate validator )
{

	if ( trg_ss == NULL )
	{
		construct( Session::defModule() );
	}
	else
	{
		construct( trg_ss->sessionDefModule() );
	}

	name_ = v_name;
	flg_ = flgs;
	kb_ = kb_init;
	val_ = validator;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
UserVar::~UserVar	( void )
{
	/* the list is allocated dinamically */
	if ( hasMultipleCallbacks() )
	{
		delete pkb_;
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UserVar::addCallback				( kbUserVarChange new_kb )
{

	if ( hasCallback() )
	{
		if ( ( flg_ & FL_MULTIPLE_KB ) != 0 )
		{ /* we already have a list */
			pkb_->append( new_kb );
		}
		else
		{ /* there is only one callback present at this time */
			QList<kbUserVarChange> * new_l = new QList<kbUserVarChange>;
			new_l->append( kb_ );
			new_l->append( new_kb );
			setFlag( FL_MULTIPLE_KB );
			pkb_ = new_l;
		}
	}
	else
	{ /* this is the first one */
		kb_ = new_kb;
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UserVar::delCallback				( kbUserVarChange the_kb )
{
	if ( hasCallback() )
	{
		if ( ( flg_ & FL_MULTIPLE_KB ) != 0 )
		{
			int i = pkb_->indexOf( the_kb );
			if ( i == -1 )
			{
				return false;
			}
			else
			{
				pkb_->removeAt( i );
				return true;
			}
		}
		else
		{
			if ( kb_ == the_kb )
			{
				kb_ = NULL;
				return true;
			}
			else
			{
				return false;
			}
		}
	}
	else
		return false;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void            UserVar::signalChange           ( void )
{
	if ( hasCallback() )
	{
		if ( ( flg_ & FL_MULTIPLE_KB ) != 0 )
		{ /* we have a list */
			for ( int i = 0; i < pkb_->count(); i++ )
			{
				(*pkb_->at( i ))( this );
			}
		}
		else
		{ /* we have only one */
			kb_( this );
		}
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			UserVar::resetContent			( void )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	intf->resetContent( &data_ );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString 		UserVar::typeName				( void )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->typeName( );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			UserVar::changeVal				( const VarStore & new_v )
{
	if ( val_ != NULL )
	{
		if ( val_( this, new_v ) )
		{
			signalChange();
			return true;
		}
		return false;
	}

	resetContent();
	data_ = new_v;
	signalChange();

	return true;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
DefVar *		UserVar::interface			( void )
{
	StoreType bt = basicType();
	if ( bt == VTY_DEFVAR )
		return data_.dfv;
	else
	{
		Q_ASSERT( ( bt < VTY_DEFVAR ) && ( bt >= 0 ) );
		Q_ASSERT( bldin_intf != NULL );
		return bldin_intf[ bt ];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString			UserVar::presentation			( void )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->presentation( &data_ );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UserVar::convToBool		( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToBool( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint16				UserVar::convToShort	( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToShort( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint32				UserVar::convToInt		( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToInt( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint64				UserVar::convToLong		( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToLong( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint8				UserVar::convToByte		( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToByte( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qreal				UserVar::convToDouble	( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToDouble( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QStringList			UserVar::convToStrLst	( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToStrLst( b_ok, uv );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString				UserVar::convToStr		( bool * b_ok, VarStore * uv )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	return intf->convToStr( b_ok, uv );
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void				UserVar::setVal		( const int * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_INTEGER );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].l = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UserVar::setVal		( const qint64 * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_INTEGER );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].l = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UserVar::setVal		( const double * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_DOUBLE );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].d = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setVal		( const bool * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_BOOL );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].b = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setVal		( const char * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_CHARACTER );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].ch = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setVal		( const QChar * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_CHARACTER );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].ch = p_list[i].unicode();
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setVal		( const QRgb * p_list, int el_cnt )
{
	UVarAry::setValArray( this, el_cnt, VTY_COLOR );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].rgb = p_list[i];
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setVal		( const QStringList p_list )
{
	UVarAry::setValArray( this, p_list.count(), VTY_STRING );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < p_list.count(); i++ )
	{
		itr[i].s.fromString( p_list.at( i )  );
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setValArray	( int el_cnt, StoreType ary_ty )
{
	UVarAry::setValArray( this, el_cnt, ary_ty );
	Q_ASSERT( ary_ty > 0 );
	VarStore * itr  = data_.ary.p_ary;
	if ( ary_ty < VTY_DEFVAR )
	{
		DefVar * intf = bldin_intf[ary_ty];
		for ( int i = 0; i < el_cnt; i++ )
		{
			intf->setDefault( &itr[i] );
		}
	}
	else
	{
		/* no known case when this is legal */
		Q_ASSERT( false );
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

void				UserVar::setCharArray	( QString src )
{

	int buf_len = src.constEnd() - src.constBegin();
	UVarAry::setValArray( this, buf_len, VTY_CHARACTER );
	VarStore * itr  = data_.ary.p_ary;
	for ( int i = 0; i < src.length(); i++ )
	{
		itr[i].ch = src.at( i ).unicode();
	}
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
bool				UserVar::save				( PgSave::IPgSave & stg )
{
	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	if ( name_.isEmpty() ) return false;


	stg.setPath( name_ );

	bool ret_v = intf->save( stg, &data_ );

	stg.cdUp();

	return ret_v;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UserVar *		UserVar::load			(
		QString s_name, Module * targ_mdl, PgSave::IPgSave &targ_i )
{
	UserVar *	ret_m;
	ret_m = new UserVar( s_name, targ_mdl );
	ret_m->load( targ_i );
	return ret_m;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UserVar::load				( PgSave::IPgSave & targ_i )
{
	resetContent();

	targ_i.setPath( name_ );

	DefVar * intf = interface();
	Q_ASSERT( intf != NULL );
	if ( name_.isEmpty() ) return false;
	return intf->load( targ_i, &data_ );

	targ_i.cdUp();
}
/* ========================================================================= */



/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
